#include "AXML.h"
#include "AString.h"
#include "ccMacros.h"
#include "ACache.h"

CAXMLNode::CAXMLNode()
{
	GUARD_FUNCTION();

	_nodes = new CAStringMap<CAXMLNodes>();
	//_nodes->autorelease();
}

CAXMLNode::~CAXMLNode()
{
	_nodes->release();
	_nodes = NULL;
}

#if 0
CAString CAXMLNode::getAttr(const CAString& name)
{
	strings items;
	
	CAStringUtils::split(name, "@", items);
	if (items.size() == 2)
	{
		CAString nodestr = items[0];
		CAString attr = items[1];

		CAXMLNode* p = getNode(nodestr);
		if (NULL != p)
		{
			return p->attrs[attr];
		}
	}
	return CAString("");
}

const vector<CAXMLNode*>& CAXMLNode::getNodes(const CAString& name)
{
}

CAXMLNode* CAXMLNode::getNode(const CAString& name)
{
	strings nodes;
	CAStringUtils::split(name, ".", nodes);

	unsigned int i;
	CAXMLNode* p = this;
	for (i = 0; i < nodes.size(); i++)
	{
		strings items;
		CAStringUtils::split(nodes[i], ":", items);
		int index = 0;
		if (items.size() == 2) index = atoi(items[1]);

		const vector<CAXMLNode*>& subs = p->nodes[items[0]];
		p = subs[index];

		if (NULL == p)
		{
			return NULL;
		}
	}
	return p;
}
#endif

CAXML::CAXML(void)
{
	this->_nodesStack.push(this);
}

CAXML::~CAXML(void)
{
	this->_nodesStack.pop();
	//_Trace("xml %s released", name().c_str());
}

CAXMLNode* CAXML::_curnode()
{
	if (_nodesStack.size() <= 0) 
		return NULL;
	return _nodesStack.top();
}

// implement pure virtual methods of CCSAXDelegator
void CAXML::startElement(void *ctx, const char *name, const char **atts)
{
	GUARD_FUNCTION();

	CAXMLNode* parent = _curnode();

	CAXMLNode* pnode = new CAXMLNode();
	pnode->setName(name);
	if(atts && atts[0])
	{
		for(int i = 0; atts[i]; i += 2) 
		{
			CAString key = (char*)atts[i];
			CAString value = (char*)atts[i+1];
			pnode->addAttr(key.c_str(), value.c_str());
		}
	}
	parent->addNode(name, pnode);
	pnode->release();
	
	_nodesStack.push(pnode);
}

void CAXML::endElement(void *ctx, const char *name)
{
	_Assert(_curnode()->name() == name);
	_nodesStack.pop();
}

void CAXML::textHandler(void *ctx, const char *ch, int len)
{
	CAString text = CAString(ch, len);
	_curnode()->setText(text.c_str());
}

const char* _cache_group = "xml";
CAXML* CAXML::parse(const char* pszFile, bool bCache)
{
	GUARD_FUNCTION();

	CAXML* pxml = NULL;

	pxml = (CAXML*)CACache::sharedCache().hit(pszFile, _cache_group);
	if (NULL != pxml)
	{
		//_Trace("used cached xml object:%s", pszFile);
		//pxml->retain();
		return pxml;
	}

	pxml = new CAXML();
	pxml->autorelease();

	CCSAXParser parser;
	
	if (false == parser.init("UTF-8") )
	{
		_Trace("xml %s load failed", pszFile);
		return NULL;
	}
	
	parser.setDelegator(pxml);

	pxml->setName(pszFile);

	parser.parse(RES(pszFile));

	if (bCache)
	{
		CAString key = pszFile;
		CACache::sharedCache().put(key.c_str(), pxml, _cache_group);
		//_Trace("cache %s xml file", pszFile);
	}
	//_Trace("xml %s loaded", pszFile);

	return pxml;
}
